/*******************************************************************************************
 *      @name   getweather.c
 *      @brief  这是在linux系统下的使用HTTP协议对心知天气服务器的天气实况的API接口进行天气请求
 *              并使用cJSON库中的函数接口实现对JSON格式
 *      @date   2025/02/26
 *      @author cecelmx@126.com
 *      @note
 *              1.HTTP协议是基于请求/响应模式，而且HTTP服务有独立的端口号，HTTP服务的端口号是80
 *              2.心知天气服务器提供的API接口地址
 *               /v3/weather/now.json?key=your_api_key&location=beijing&language=en&unit=c
 *
 *              3.心知天气最好是使用gethostbyname来进行域名的解析，得到服务器地址116.62.81.138
 *
 *              4.心知天气返回的响应体是JSON格式，并且需要把APIKEY更为自己的密钥
 *
 *              5.需要包含cJSON.c和cJSON.h
 *
 *      @version  xx.xx.xx   主版本号.次版本号.修正版本号
 *
 *      CopyRight (c)   2024-2025   Your Name     All Right Reserved
 *
 * ****************************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <netdb.h>
#include "cJSON.h"

// 缓冲区大小
#define BUFSIZE 1024

// 心知天气API的密钥，需要修改为自己的密钥
#define API_KEY "S5jYTIuliBSEQmhkX"

// HTTP服务的端口
#define HTTP_PORT 80

// 聚合API的URL
#define SERVER_URL "/v3/weather/now.json"

// 聚合API的IP
#define SERVER_IP "116.62.81.138"

// 聚合API的域名
#define SERVER_DOMAIN "api.seniverse.com"

int main(int argc, char **argv)
{
    char recvbuf[BUFSIZE] = {0}; // 存储响应内容
    char request[BUFSIZE] = {0}; // 存储请求内容

    // 1.创建TCP套接字,HTTP协议是基于TCP协议实现的
    int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == tcp_socket)
    {
        fprintf(stderr, "create tcp socket error,%s\n", strerror(errno));
        exit(-1);
    }

    // 2.向心知天气API的服务器发起连接请求
    struct sockaddr_in dest = {0};               // IPv4地址格式的实例
    dest.sin_family = AF_INET;                   // IPv4协议族
    dest.sin_port = htons(HTTP_PORT);            // 目标端口，需要转换为网络字节序
    dest.sin_addr.s_addr = inet_addr(SERVER_IP); // 目标地址，需要转换为网络字节序

    if (-1 == connect(tcp_socket, (struct sockaddr *)&dest, sizeof(dest)))
    {
        fprintf(stderr, "connect error,%s\n", strerror(errno));
        exit(-2);
    }

    printf("connect ok\n");

    for (;;)
    {
        // 3.连接成功后，可以向服务器发起请求，需要构造请求内容
        char local[64] = {0};
        memset(request, 0, BUFSIZE); // 清空接收缓冲区
        printf("请输入城市名称(拼音，例如Beijing):");
        scanf("%s", local);

        sprintf(request, "GET %s?key=%s&location=%s&language=en&unit=c HTTP/1.1\r\n"
                         "Host: %s\r\n"
                         "\r\n",
                SERVER_URL, API_KEY, local, SERVER_DOMAIN);
        // 4.发送请求
        send(tcp_socket, request, strlen(request), 0); // 向聚合API服务器发送请求
        printf("send ok\n");

        // 5.等待心知天气API的响应内容  先返回响应头部,再返回响应Body
        recv(tcp_socket, recvbuf, sizeof(recvbuf), 0); // 先返回响应头，默认会阻塞
        memset(recvbuf, 0, BUFSIZE);                   // 清空接收缓冲区

        recv(tcp_socket, recvbuf, sizeof(recvbuf), 0); // 读取数据，默认会阻塞
        printf("%s\n", recvbuf);

        // 6.解析JSON格式的字符串
        cJSON *root = cJSON_Parse(recvbuf);
        // char *string = cJSON_Print(results_obj);

        // printf("json string:%s\n", string);

        // 7.获取result的值
        cJSON *results_obj = cJSON_GetObjectItem(root, "results");

        // 8.result的值是数组，并只有一个对象
        cJSON *results_val = cJSON_GetArrayItem(results_obj, 0);

        // 9.从对象中找"now"
        cJSON *now_obj = cJSON_GetObjectItem(results_val, "now");

        // 10.从对象中找"temperature"
        cJSON *temperature_obj = cJSON_GetObjectItem(now_obj, "temperature");

        printf("temp:%s\n", temperature_obj->valuestring);
        memset(recvbuf, 0, BUFSIZE); // 清空接收缓冲区
    }

    return 0;
}
